package com.ikingtech.framework.sdk.core.configuration;

import com.ikingtech.framework.sdk.context.security.Identity;
import com.ikingtech.framework.sdk.context.security.Me;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.ThreadContext;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.CollectionUtils;

import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 异步线程配置
 *
 * @author tie yan
 */
@Slf4j
@EnableAsync
public class AsyncConfiguration implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        threadPool.setCorePoolSize(50);
        // 设置最大线程数
        threadPool.setMaxPoolSize(2000);
        // 设置队列容量
        threadPool.setQueueCapacity(100000);
        // 设置线程活跃时间（秒）
        threadPool.setKeepAliveSeconds(180);
        // 等待所有任务结束后再关闭线程池
        threadPool.setWaitForTasksToCompleteOnShutdown(true);
        // 该方法用来设置线程池中任务的等待时间,如果超过这个时间还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住
        threadPool.setAwaitTerminationSeconds(60 * 15);
        // 设置默认线程名称
        threadPool.setThreadNamePrefix("Async-");
        // 设置拒绝策略
        threadPool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
        threadPool.setTaskDecorator(runnable -> {
            // 线程上下文透传
            Map<String, String> threadContext = ThreadContext.getContext();
            Identity currentUser = Me.info();
            return () -> {
                if (!CollectionUtils.isEmpty(threadContext)) {
                    ThreadContext.putAll(threadContext);
                }
                if (null != currentUser) {
                    Me.set(currentUser);
                }
                runnable.run();
            };
        });
        threadPool.initialize();
        return threadPool;
    }

    /**
     * 统一处理异常
     */
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (throwable, method, objects) -> log.error("-- exception handler -- " + throwable + "-- method -- " + method + "-- objects -- " + Arrays.toString(objects));
    }
}
